<?php
/**
 * Created by PhpStorm.
 * User: tomxia
 * Date: 2017/8/2
 * Time: 18:05
 * @desc  点赞处理类
 */


namespace app\cls\tom;
class Praise
{
    /**
     * @var string  用户的唯一标识符
     */
    private $user_identity;
    /**
     * @var string 要点赞的类型 根据类型生成redis key
     */
    private $praise_type;
    /**
     * @var string 点赞事务唯一标识符
     */
    private $identity;
    /**
     * @var \Redis redis实例化对象
     */
    private $redis;
    /**
     * @var bool 是否延迟点赞
     */
    public $is_delay = false;

    /**
     * @desc hash 个数
     * @var int
     */
    public $hash_nums = 100;
    /**
     * @desc hash位数 10=>2 100=>3 ...
     * @var int
     */
    public $hash_bit =  3;

    /**
     * @var string redis的key前缀
     */
    public $keyPrefix = REDIS_PREFIX;


    public function __construct($user_id = "",$identity = "",\Redis $redis = NULL,$praise_type="")
    {
        $this->user_identity = $user_id;
        $this->identity = $identity;
        $this->redis = $redis;
        $this->praise_type = $praise_type;
    }

    /**
     * @desc 设置用户标识符
     * @param $user_id
     */
    public function setUserIdentity($user_id)
    {
        $this->user_identity = $user_id;
    }

    /**
     * @desc 设置视频标识符
     * @param $identity
     * @internal param $video_id
     */
    public function setIdentity($identity)
    {
        $this->identity = $identity;
    }

    /**
     * @desc
     * @param $redis
     */
    public function setRedis($redis)
    {
        $this->redis = $redis;
    }

    /**
     * @param string  $praise_type 要点赞的类型
     */
    public function setPraiseType($praise_type)
    {
        $this->praise_type = $praise_type;
    }


    /**
     * @desc 获取存放加权总点赞数的hash key
     * @return mixed
     */
    public function getTotalKey()
    {
        return Tools::getHashSuffixByUUID($this->identity,"{$this->keyPrefix}{$this->praise_type}_PRAISE_TOTAL_",$this->hash_nums,$this->hash_bit);
    }
    /**
     * @desc 获取用户点赞的key
     */
    public function getUserClickKey()
    {
        return "{$this->keyPrefix}PRAISE_{$this->praise_type}_".$this->user_identity."_".$this->identity;
    }

    /**
     * @desc 检查对象的必要参数
     * @throws \Exception
     */
    public function checkRequireParam()
    {
        if(empty($this->identity)){
            throw new \Exception("缺少被点赞的uuid");
        }

        if(empty($this->redis)){
            throw new \Exception("缺少redis实例");
        }
    }

    /**
     * 点赞是否过期，如果为true 请设置$expire_in过期时间
     * @var bool
     */
    public $is_expire = true;
    /**
     * @desc 点一次赞的过期时间，过期之后又可以继续点赞
     * @var int
     */
    public $expires_in = 3600*24;

    /**
     * @desc 用户点赞
     * @param null $num
     * @param bool $isRePraise 是否可以重复点赞
     * @return int
     * @throws \Exception
     */
    public function clickPraise($num=null,$isRePraise = true)
    {
        $this->checkRequireParam();
        //1.获取redis key
        $virtualTotalKey = $this->getTotalKey();
        if($isRePraise){
            //表示可以无限点赞
            $nums = $this->redis->hIncrBy($virtualTotalKey,$this->identity,$num ? (int)$num:1);
            if(!empty($this->user_identity)){
                $userClickKey = $this->getUserClickKey();
                $this->redis->set($userClickKey,1);
            }
            return $nums;
        }else{
            if(empty($this->user_identity)){
                throw  new \Exception("非重复点赞必须设置用户客户端标识");
            }
            $userClickKey = $this->getUserClickKey();
            $userPraiseNum = $this->redis->get($userClickKey);
            if($userPraiseNum){
                //已经被点过赞
                return  false;
            }else{
                if($this->is_expire){
                    $this->redis->setEx($userClickKey,$this->expires_in,1);
                }else{
                    $this->redis->set($userClickKey,1);
                }
                $nums = $this->redis->hIncrBy($virtualTotalKey,$this->identity,$num ? (int)$num:1);
                return $nums;
            }
        }
    }

    /**
     * @desc 取消点赞
     * @throws \Exception
     */
    public function cancelClickPraise()
    {
        $this->checkRequireParam();

        if(empty($this->user_identity)){
            throw new \Exception("取消点赞必须要用户ID");
        }
        //可以优化，把点赞key的后缀存放在$this->suffix中
        $key1 = $this->getTotalKey();
        $key2 = $this->getUserClickKey();

        $isPraise = $this->redis->get($key2);
        if($isPraise){
            $this->redis->del($key2);//清理垃圾key
            $nums = $this->redis->hIncrBy($key1,$this->identity,-1);
        }else{
            $nums = $this->redis->hget($key1, $this->identity);
        }
        return $nums;
    }

    /**
     * @desc 获取用户点赞的信息
     * @return array
     * @throws \Exception
     */
    public function getClickPraiseInfo()
    {
        $this->checkRequireParam();

        //点赞总的key
        $key1 = $this->getTotalKey();
        //获取点赞次数
        $videoInfo["praise"] = (int) $this->redis->hget($key1,$this->identity);
        if(!empty($this->user_identity)){
            $key3 = $this->getUserClickKey();
            $praiseNums = $this->redis->get($key3);
            if((int)$praiseNums>0){
                $videoInfo["is_praise"] = 1;
            }else{
                $videoInfo["is_praise"] = 0;
            }
        }
        return $videoInfo;
    }

}